/*****************************************************************************
*    Ali Corp. All Rights Reserved. 2005 Copyright (C)
*
*    File:    pan_sm1668.c
*
*    Description:    This file contains all functions definition
*		             of Front Panel driver.
*
*    Note:
*    This driver is used to support sm1668 front panel controller. 
*
*    History:
*           Date            Athor        Version          Reason
*	    ============	=============	=========	=================
*	1.	2007.5.25      Goliath Peng        Ver 0.1     Create file.
*****************************************************************************/

#include <sys_config.h>

#include <retcode.h>
#include <types.h>

#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <osal/osal.h>
#include <hal/hal_gpio.h>
#include <hld/hld_dev.h>
#include <hld/pan/pan.h>
#include <hld/pan/pan_dev.h>
#include "pan_sm1668.h"

static UINT8 clk_id;
static UINT8 data_in; //data input to sm1668
static UINT8 data_out; //data output from sm1668
static UINT8 strobe_id;
/*this array defines number to digital conversion
*
 *      ###b7##
 *    b2#     #b6
 *      ###b1##
 *    b3#     #b5
 *      ###b4##  #b0#
 */
#if 0
static struct led_bitmap bitmap_table[] =
{
	{'.', 0xfe}, /* Let's put the dot bitmap into the table */
	{'0', 0x03}, {'1', 0x9f}, {'2', 0x25}, {'3', 0x0d},
	{'4', 0x99}, {'5', 0x49}, {'6', 0x41}, {'7', 0x1f},
	{'8', 0x01}, {'9', 0x09}, {'a', 0x11}, {'A', 0x11},
	{'b', 0xc1}, {'B', 0xc1}, {'c', 0x63}, {'C', 0x63},
	{'d', 0x85}, {'D', 0x85}, {'e', 0x61}, {'E', 0x61},
	{'f', 0x71}, {'F', 0x71}, {'g', 0x09}, {'G', 0x43},
	{'h', 0x91}, {'H', 0x91}, {'i', 0xdf}, {'I', 0xf3},
	{'j', 0x8f}, {'J', 0x8f}, {'l', 0xe3}, {'L', 0xe3},
	{'n', 0xd5}, {'N', 0x13}, {'o', 0xc5}, {'O', 0x03},
	{'p', 0x31}, {'P', 0x31}, {'q', 0x19}, {'Q', 0x19},
	{'r', 0xf5}, {'R', 0x11}, {'s', 0x49}, {'S', 0x49},
	{'t', 0xe1}, {'T', 0x73}, {'u', 0x83}, {'U', 0x83},
	{'y', 0x89}, {'Y', 0x89}, {'z', 0x25}, {'Z', 0x25},
	{':', 0xfe}, {'-', 0xfd}, {'_', 0xef}, {' ', 0xff},
};
#endif

#ifdef _BOARD_DB_C3047_T2_01V01_
// h g f e d c b a
static struct led_bitmap bitmap_table[] =
{
	{'.', 0x80}, /* Let's put the dot bitmap into the table */
	{'0', 0x3F}, {'1', 0x06}, {'2', 0x6B}, {'3', 0x4F},
	{'4', 0x56}, {'5', 0x5D}, {'6', 0x7D}, {'7', 0x07},
	{'8', 0x7F}, {'9', 0x5F}, {'a', 0x6F}, {'A', 0x77},
	{'b', 0x7C}, {'B', 0x7C}, {'c', 0x68}, {'C', 0x39},
	{'d', 0x6E}, {'D', 0x6E}, {'e', 0x79}, {'E', 0x79},
	{'f', 0x71}, {'F', 0x71}, {'g', 0xf6}, {'G', 0xbc},
	{'h', 0x74}, {'H', 0x76}, {'i', 0x20}, {'I', 0x30},
	{'j', 0x2E}, {'J', 0x2E}, {'l', 0x38}, {'L', 0x38},
	{'n', 0x64}, {'N', 0x37}, {'o', 0x6C}, {'O', 0x3F},
	{'p', 0x73}, {'P', 0x73}, {'q', 0x57}, {'Q', 0x57},
	{'r', 0x60}, {'R', 0x60}, {'s', 0x5D}, {'S', 0x5D},
	{'t', 0x78}, {'T', 0x78}, {'u', 0x2C}, {'U', 0x3E},
	{'y', 0x5E}, {'Y', 0x5E}, {'z', 0xea}, {'Z', 0xea},
	{':', 0x80}, {'-', 0x40}, {'_', 0x08}, {' ', 0x00},
};
#else
// h g f e d c b a
static struct led_bitmap bitmap_table[] =
{
	{'.', 0x80}, /* Let's put the dot bitmap into the table */
	{'0', 0x3F}, {'1', 0x06}, {'2', 0x5B}, {'3', 0x4F},
	{'4', 0x66}, {'5', 0x6D}, {'6', 0x7D}, {'7', 0x07},
	{'8', 0x7F}, {'9', 0x6F}, {'a', 0x5F}, {'A', 0x77},
	{'b', 0x7C}, {'B', 0x7C}, {'c', 0x58}, {'C', 0x39},
	{'d', 0x5E}, {'D', 0x5E}, {'e', 0x79}, {'E', 0x79},
	{'f', 0x71}, {'F', 0x71}, {'g', 0xf6}, {'G', 0xbc},
	{'h', 0x74}, {'H', 0x76}, {'i', 0x10}, {'I', 0x30},
	{'j', 0x1E}, {'J', 0x1E}, {'l', 0x38}, {'L', 0x38},
	{'n', 0x54}, {'N', 0x37}, {'o', 0x5C}, {'O', 0x3F},
	{'p', 0x73}, {'P', 0x73}, {'q', 0x67}, {'Q', 0x67},
	{'r', 0x50}, {'R', 0x50}, {'s', 0x6D}, {'S', 0x6D},
	{'t', 0x78}, {'T', 0x78}, {'u', 0x1C}, {'U', 0x3E},
	{'y', 0x6E}, {'Y', 0x6E}, {'z', 0xda}, {'Z', 0xda},
	{':', 0x01}, {'-', 0x40}, {'_', 0x08}, {' ', 0x00},
};
#endif


#define PAN_SM1668_CHAR_LIST_NUM sizeof(bitmap_table)/sizeof(struct led_bitmap)

static struct pan_sm1668_info
{
	struct pan_hw_info *hw_info;
	int					bitmap_len;
	struct led_bitmap  *bitmap_list;
	UINT8				dis_buff[8];
	UINT32				dis_id;
	UINT8				led_buff;
	UINT8				dotmap;
	UINT8				colonmap;
	UINT8				blankmap;
	UINT32				cnt_repeat_first;
	UINT32				cnt_repeat;
	UINT32				key_cnt;			/* Continue press key times */
	UINT32				keypress_cnt;		/* Continue press key counter */
	UINT32 				keypress_intv;		/* Continue press key interval */
	UINT32 				keypress_num;		/* Pressed key COM index saver */
	UINT32				keypress_bak;		/* Pressed key saver */
	UINT8 				cur_dis_mem[5][2];
	UINT8 				new_dis_mem[5][2];
} pan_sm1668_data;

static INT32 pan_sm1668_open(struct pan_device *dev);
static INT32 pan_sm1668_close(struct pan_device *dev);
static INT32 pan_sm1668_ioctl(struct pan_device *dev, INT32 cmd, UINT32 param);
static void  pan_sm1668_display(struct pan_device *dev, char *data, UINT32 len);
static void  pan_sm1668_interrupt(UINT32 param);

/* Name for the panel, the last character must be Number for index */
static char  pan_sm1668_name[HLD_MAX_NAME_SIZE] = "PAN_SM1668_0";

#ifndef _BOARD_DB_C3047_T2_01V01_
#ifndef C3041
#define GPIO_OD
#endif
#endif

#ifdef GPIO_OD

void set_gpio_high(int gpio_pin)
{
	HAL_GPIO_BIT_DIR_SET(gpio_pin, HAL_GPIO_I_DIR);
	HAL_GPIO_BIT_SET(gpio_pin, 1);
}

void set_gpio_low(int gpio_pin)
{
	HAL_GPIO_BIT_SET(gpio_pin, 0);
	HAL_GPIO_BIT_DIR_SET(gpio_pin, HAL_GPIO_O_DIR);
}


void sm1668_write(UINT8 * byte, UINT32 len)
{
	UINT32 i;
	UINT8 j;
	
	set_gpio_high(strobe_id);//STB high
	osal_delay(1);
	set_gpio_high(clk_id);//clk high
	osal_delay(1);
	set_gpio_low(strobe_id);//STB low
	osal_delay(1);
	for(j = 0; j<len; j++)
	{
		for(i=0; i<8; i++)
		{
			set_gpio_low(clk_id);//clk low
			if ((byte[j]>>i)&0x01)
				set_gpio_high(data_in);
			else
				set_gpio_low(data_in);
			osal_delay(PW_CLK);
			set_gpio_high(clk_id);//clk high, latch data
			osal_delay(PW_CLK);
		}
		osal_delay(T_WAIT);
	}
	set_gpio_high(strobe_id);//STB high
}

void sm1668_write_read(UINT8 * byte, UINT32 len_in, UINT32 len_out)
{
	UINT32 i;
	UINT8 j;

	set_gpio_high(strobe_id);//STB high
	osal_delay(1);
	set_gpio_high(clk_id);//clk high
	osal_delay(1);
	set_gpio_low(strobe_id);//STB low
	osal_delay(1);
	for(j = 0; j<len_in; j++)
	{
		for(i=0; i<8; i++)
		{
			set_gpio_low(clk_id);//clk low
			if ((byte[j]>>i)&0x01)
				set_gpio_high(data_in);
			else
				set_gpio_low(data_in);
			osal_delay(PW_CLK);
			set_gpio_high(clk_id);//clk high, latch data
			osal_delay(PW_CLK);
		}
		osal_delay(T_WAIT);
	}
	
	HAL_GPIO_BIT_DIR_SET(data_out, HAL_GPIO_I_DIR);
	for(j = 0; j<len_out; j++)
	{
		byte[j] = 0;
		for(i=0; i<8; i++)
		{
			set_gpio_low(clk_id);//clk low
			osal_delay(PW_CLK);
			byte[j] |= HAL_GPIO_BIT_GET(data_out)<<i;
			set_gpio_high(clk_id);//clk high, latch data
			osal_delay(PW_CLK);
		}
		osal_delay(T_WAIT);
	}
	set_gpio_high(strobe_id);//STB high
}

#else
void sm1668_write(UINT8 * byte, UINT32 len)
{
	UINT32 i;
	UINT8 j;
	
	HAL_GPIO_BIT_SET(clk_id, 1);//clk high
	
	HAL_GPIO_BIT_DIR_SET(clk_id, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_DIR_SET(data_in, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_DIR_SET(strobe_id, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(strobe_id, 1);//STB high
	osal_delay(1);
	HAL_GPIO_BIT_SET(clk_id, 1);//clk high
	osal_delay(1);
	HAL_GPIO_BIT_SET(strobe_id, 0);//STB low
	osal_delay(1);
	for(j = 0; j<len; j++)
	{
		for(i=0; i<8; i++)
		{
			HAL_GPIO_BIT_SET(clk_id, 0);//clk low
			HAL_GPIO_BIT_SET(data_in, (byte[j]>>i)&0x01);
			osal_delay(PW_CLK);
			HAL_GPIO_BIT_SET(clk_id, 1);//clk high, latch data
			osal_delay(PW_CLK);
		}
		osal_delay(T_WAIT);
	}
	HAL_GPIO_BIT_SET(strobe_id, 1);//STB high
}

void sm1668_write_read(UINT8 * byte, UINT32 len_in, UINT32 len_out)
{
	UINT32 i;
	UINT8 j;

	HAL_GPIO_BIT_SET(clk_id, 1);//clk high
	
	HAL_GPIO_BIT_DIR_SET(clk_id, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_DIR_SET(data_in, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_DIR_SET(strobe_id, HAL_GPIO_O_DIR);
	
	HAL_GPIO_BIT_SET(strobe_id, 1);//STB high
	osal_delay(1);
	HAL_GPIO_BIT_SET(clk_id, 1);//clk high
	osal_delay(1);
	HAL_GPIO_BIT_SET(strobe_id, 0);//STB low
	osal_delay(1);
	for(j = 0; j<len_in; j++)
	{
		for(i=0; i<8; i++)
		{
			HAL_GPIO_BIT_SET(clk_id, 0);//clk low
			HAL_GPIO_BIT_SET(data_in, (byte[j]>>i)&0x01);
			osal_delay(PW_CLK);
			HAL_GPIO_BIT_SET(clk_id, 1);//clk high, latch data
			osal_delay(PW_CLK);
		}
		osal_delay(T_WAIT);
	}
	HAL_GPIO_BIT_DIR_SET(data_out, HAL_GPIO_I_DIR);
	for(j = 0; j<len_out; j++)
	{
		byte[j] = 0;
		for(i=0; i<8; i++)
		{
			HAL_GPIO_BIT_SET(clk_id, 0);//clk low
			osal_delay(PW_CLK);
			byte[j] |= HAL_GPIO_BIT_GET(data_out)<<i;
			HAL_GPIO_BIT_SET(clk_id, 1);//clk high, latch data
			osal_delay(PW_CLK);
		}
		osal_delay(T_WAIT);
	}
	HAL_GPIO_BIT_SET(strobe_id, 1);//STB high
}

#endif

#ifdef _BOARD_DB_C3047_T2_01V01_
void pan_sm1668_set_mode(UINT8 mode) 
{
	UINT8 cmd;
	switch(mode)
	{
		case 0:
			cmd=CMD4_PREFIX|BYTES4_SG13;
			break;
		case 1:
			cmd=CMD4_PREFIX|BYTES5_SG12;
			break;
		case 2:
			cmd=CMD4_PREFIX|BYTES6_SG11;
			break;
		case 3:
			cmd=CMD4_PREFIX|BYTES7_SG10;
			break;
		default:
			cmd=CMD4_PREFIX|BYTES4_SG13;
			break;		

	}
	osal_interrupt_disable();
	sm1668_write(&cmd, 1);
	osal_interrupt_enable();
}
#endif

void pan_sm1668_led_onoff(UINT8 on_off) // 1: on, 0: off
{
	UINT8 cmd;
	if(on_off)
		cmd = LED_ON;
	else
		cmd = LED_OFF;
	osal_interrupt_disable();
	sm1668_write(&cmd, 1);
	osal_interrupt_enable();
}

 void pan_sm1668_update_led(UINT8 addr, UINT8 * byte, UINT8 len)
 {
 
 	UINT8 cmd;	
 	UINT8 cmd_seq[11]; 
	UINT32 i;

	if(len<1||len>10)
		return;
	if(len==1)
		cmd = CMD1_WRITE_FIXED;
	else 
		cmd = CMD1_WRITE_INCRE;
	cmd_seq[0] = CMD2_ADDR(addr);
	MEMCPY(&cmd_seq[1], byte, len);	
	osal_interrupt_disable();	
	sm1668_write(&cmd, 1);
	sm1668_write(cmd_seq, 1+len);
	osal_interrupt_enable();
 }

void pan_sm1668_led_init(struct pan_device *dev)
 {
 	struct pan_sm1668_info *tp = (struct pan_sm1668_info *)dev->priv;
 	UINT8 i; 
	for(i = 0; i<5; i++)
	{
		tp->new_dis_mem[i][0] |= tp->blankmap<<2;
		tp->new_dis_mem[i][1] |= tp->blankmap>>6;
		tp->cur_dis_mem[i][0] |= tp->blankmap<<2;
		tp->cur_dis_mem[i][1] |= tp->blankmap>>6;
		
#ifdef _BOARD_DB_C3047_T2_01V01_
		if(GRE_LED_CONTROL_SG<8)//show green led
		{
			tp->new_dis_mem[i][0]|=1<<GRE_LED_CONTROL_SG;
			tp->cur_dis_mem[i][0]|=1<<GRE_LED_CONTROL_SG;
		}
		else
		{
			tp->new_dis_mem[i][1]|=1<<(GRE_LED_CONTROL_SG-8);
			tp->cur_dis_mem[i][1]|=1<<(GRE_LED_CONTROL_SG-8);
		}
#endif
	}
#ifdef _BOARD_DB_C3047_T2_01V01_
	pan_sm1668_set_mode(0);
#endif
	pan_sm1668_update_led(0x00, &(tp->cur_dis_mem[0][0]), 10);
	pan_sm1668_led_onoff(1);
 }


#ifdef _BOARD_DB_C3047_T2_01V01_
UINT32 vfdk_to_hostk(UINT8 vkey,UINT8 byte_inx)
{
	const VFD_HOST_KMAP vhkarr[]={
		
		{VFD_POWER_KEY,0xFFFF0010,1},//V_KEY_POWER
	    {VFD_LEFT_KEY,0xFFFF0040,0},//VFD_DVB_DVD     
		{VFD_RIGHT_KEY,0xFFFF0008,0},
		{VFD_UP_KEY,0xFFFF0020,0},//V_KEY_UP 
		{VFD_DOWN_KEY,0xFFFF0001,0},//V_KEY_DOWN 0x00bfb847
		{VFD_KEY_NULL,PAN_KEY_INVALID} ,
	};
	//if(vkey!=VFD_KEY_NULL)
	//	libc_printf("----------null key=%x,byte_inx:%d\n",vkey,byte_inx);
	
	UINT8 i;
	for(i=0;i<sizeof(vhkarr)/2;i++)
	
	{
	//if(byte_inx!=NULL)
	//libc_printf("vhkarr[i].vfd_k=%d,vkey=%d,vhkarr[i].byte_inx=%d,byte_inx=%d\n",vhkarr[i].vfd_k,vkey,vhkarr[i].byte_inx,byte_inx);
	
		if((vhkarr[i].vfd_k==vkey)&&(byte_inx==vhkarr[i].byte_inx))
			return vhkarr[i].host_k;
	}	
	return PAN_KEY_INVALID;

}
UINT32 vfd_scankey(void)
{
   	UINT8 KEY1[VFD_KEY_ARRAY_BYTE_SIZE];
	UINT8 i,location,key;
	KEY1[0] = VFD_CMD_KEY_SCAN;
	UINT8 b_inx;

	
    HAL_GPIO_BIT_DIR_SET(strobe_id, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(strobe_id,0);//STB LOW
	osal_delay(1);
	sm1668_write_read(KEY1, 1, VFD_KEY_ARRAY_BYTE_SIZE);
	HAL_GPIO_BIT_SET(strobe_id, 1);//STB HIGH
	osal_delay(1);
	for (i =0; i < VFD_KEY_ARRAY_BYTE_SIZE; i++)
	{
		key = KEY1[i];
		//libc_printf("KEY1[%d]=%d\n",i,KEY1[i]);
		if ((key!=VFD_KEY_NULL)&&(0!=key))
		{
			/*location=0;
			while (!(key & 0x01))
			{
				location++;
				key >>= 1;
			};
			location += i * 8;*/	
			b_inx=i;
			break;
		}
	}
	if(i>=VFD_KEY_ARRAY_BYTE_SIZE)
		return vfdk_to_hostk(VFD_KEY_NULL,NULL);
	else
		return vfdk_to_hostk(key,b_inx);


}
 void pan_sm1668_read_key(UINT32 * byte, UINT8 len)
 {

  	UINT8 cmd_seq[5];
	*byte =  vfd_scankey();
 }

#else
 void pan_sm1668_read_key(UINT8 * byte, UINT8 len)
 {

  	UINT8 cmd_seq[5];

	if(len>5)
		return;
	cmd_seq[0] = CMD1_READ;
	osal_interrupt_disable();
	sm1668_write_read(cmd_seq, 1, 5);

	osal_interrupt_enable();
	MEMCPY(byte, cmd_seq, len);
 }
#endif
/*
 * 	Name		:   pan_sm1668_attach()
 *	Description	:   Panel init funciton should be called in
 *                  system boot up.
 *	Parameter	:	None
 *	Return		:	INT32				: return value
 *
 */
__ATTRIBUTE_REUSE_
INT32 pan_sm1668_attach(struct pan_configuration *config)
{
	struct pan_device *dev;
	struct pan_sm1668_info *tp;
	int i, j;
	if (config == NULL || config->hw_info == NULL)
	{
		return ERR_FAILUE;
	}
	dev = dev_alloc(pan_sm1668_name, HLD_DEV_TYPE_PAN, sizeof(struct pan_device));
	if (dev == NULL)
	{
		PRINTF("Error: Alloc front panel device error!\n");
		return ERR_NO_MEM;
	}
	/* Alloc structure space of private */
	MEMSET(&pan_sm1668_data, 0, sizeof(struct pan_sm1668_info));

	if (config->bitmap_list == NULL)
	{
		pan_sm1668_data.bitmap_len = PAN_SM1668_CHAR_LIST_NUM;
		pan_sm1668_data.bitmap_list = &(bitmap_table[0]);
	}
	else
	{
		pan_sm1668_data.bitmap_len = config->bitmap_len;
		pan_sm1668_data.bitmap_list = config->bitmap_list;
	}
	pan_sm1668_data.hw_info = config->hw_info;

	dev->priv = &pan_sm1668_data;

	dev->led_num = pan_sm1668_data.hw_info->num_com;
	dev->key_num = 0;

	/* Function point init */
	dev->init = pan_sm1668_attach;
	dev->open = pan_sm1668_open;
	dev->stop = pan_sm1668_close;
	dev->do_ioctl = pan_sm1668_ioctl;
	dev->display =pan_sm1668_display;
	dev->send_data = NULL;
	dev->receive_data = NULL;

	/* Add this device to queue */
	if (dev_register(dev) != SUCCESS)
	{
		PRINTF("Error: Register panel device error!\n");
		dev_free(dev);
		return ERR_NO_DEV;
	}
	//pan_common_gpio_init(config->hw_info, 1);
	tp = (struct pan_sm1668_info *)dev->priv;
	for(i=0; i<4; i++)
	{
		HAL_GPIO_BIT_DIR_SET(tp->hw_info->lbd[i].position, tp->hw_info->lbd[i].io);
		HAL_GPIO_BIT_SET(tp->hw_info->lbd[i].position, !(tp->hw_info->lbd[i].polar));
	}
	/* Set default bitmap in buffer. At same time get the dot bitmap. */
	for (i = 0; i < tp->bitmap_len; i++)
	{
		if (' ' == tp->bitmap_list[i].character)
		{
			tp->blankmap = tp->bitmap_list[i].bitmap;
			for (j = 0; j < tp->hw_info->num_com; j++)
				tp->dis_buff[j] = tp->blankmap;
		}
		else if ('.' == tp->bitmap_list[i].character)
		{
			tp->dotmap = tp->bitmap_list[i].bitmap;
		}
		else if (':' == tp->bitmap_list[i].character)
		{
			tp->colonmap = tp->bitmap_list[i].bitmap;
		}
	}
	/* If is shadow scan, all key scan per 1mS interrupt, else... */
	if (tp->hw_info->type_scan == 1)
	{
		tp->cnt_repeat_first = tp->hw_info->intv_repeat_first;
		tp->cnt_repeat = tp->hw_info->intv_repeat;
	} else
	{
		tp->cnt_repeat_first = tp->hw_info->intv_repeat_first / tp->hw_info->num_com;
		tp->cnt_repeat = tp->hw_info->intv_repeat / tp->hw_info->num_com;
	}

	strobe_id = tp->hw_info->flatch.position;
	clk_id = tp->hw_info->fclock.position;
	data_in = tp->hw_info->fdata.position;
	data_out = tp->hw_info->fdata.position;
	return SUCCESS;
}

static INT32 pan_sm1668_ioctl(struct pan_device *dev, INT32 cmd,
								UINT32 param)
{
	switch (cmd)
	{
		case PAN_DRIVER_ATTACH:
			break;
		case PAN_DRIVER_SUSPEND:
			break;
		case PAN_DRIVER_RESUME:
			break;
		case PAN_DRIVER_DETACH:
			break;
		case PAN_DRIVER_READ_LNB_POWER:
			break;
		default:
			break;
	}

	return SUCCESS;
}

/*
* Name          :   pan_sm1668_open()
* Description   :   Open front panel
* Parameter     :   struct pan_device *dev
* Return        :   void
*/
static INT32  pan_sm1668_open(struct pan_device *dev)
{
	struct pan_sm1668_info *tp = (struct pan_sm1668_info *)dev->priv;
	struct pan_hw_info *hp = tp->hw_info;
	UINT8 led_data = 0;
	int i;

	tp->keypress_intv = tp->cnt_repeat_first/10;
	tp->keypress_bak = PAN_KEY_INVALID;
	tp->keypress_num = tp->hw_info->num_com;
	tp->keypress_cnt = 0;
	tp->key_cnt = 0;

	/* Init LBD to invalid state */
	if (hp->type_kb & 0x02)
	{
		for (i = 0; i < 4; i++)
		{
			if (hp->lbd[i].polar == 0)	/* Set to invalidate status */
				led_data |= (1 << hp->lbd[i].position);
		}
		led_data &= 0xff;
	}
	pan_sm1668_data.led_buff = led_data;
	pan_sm1668_led_init(dev);
#ifdef _DEBUG_VERSION_
	if (tp->hw_info->type_irp != 0)
		irc_m6303irc_init(tp->hw_info);
#endif
	/* Register an 1mS cycle interrupt ISR */
	osal_interrupt_register_lsr(7, pan_sm1668_interrupt, (UINT32)dev);

	return SUCCESS;
}


/*
* Name          :   pan_sm1668_close()
* Description   :   close front panel
* Parameter     :   struct pan_device *dev
* Return        :   void
*/
static INT32  pan_sm1668_close(struct pan_device *dev)
{
	struct pan_sm1668_info *tp = (struct pan_sm1668_info *)dev->priv;
	int i;

#ifdef _DEBUG_VERSION_
	if (tp->hw_info->type_irp != 0)
		irc_m6303irc_close();
#endif

	/* Un-register an 1mS cycle interrupt ISR */
	osal_interrupt_unregister_lsr(7, pan_sm1668_interrupt);

	/* Clear last displayed char map. */
	
	for(i = 0; i<5; i++)
	{
	
		tp->cur_dis_mem[i][0] = tp->dis_buff[i];
	
	}
	pan_sm1668_update_led(0x00, &(tp->cur_dis_mem[0][0]), 10);
	
	pan_sm1668_led_onoff(0);
	return SUCCESS;
}


/*
* Name          :   pan_sm1668_interrupt()
* Description   :   front panel interrupt function
* Parameter     :   None
* Return        :   void
*/
static void  pan_sm1668_interrupt(UINT32 param)
{
	struct pan_device *dev = (struct pan_device *)param;
	struct pan_sm1668_info *tp = (struct pan_sm1668_info *)dev->priv;
	UINT32 keypress = PAN_KEY_INVALID;
	UINT32 key_matrix = 0;
	struct pan_key key;
	static UINT8 cnt = 0;
	static UINT8 tmpcnt = 0;
	UINT32 i;

	if (tmpcnt++<10)
		return;
	tmpcnt = 0;
	
	//pan_sm1668_update_led(0, &tp->cur_dis_mem[0][0], 10);
	//pan_sm1668_led_onoff(1);

#ifdef _BOARD_DB_C3047_T2_01V01_
	pan_sm1668_read_key(&key_matrix, 5);
	keypress=key_matrix;
#else
	pan_sm1668_read_key((UINT8 *)(&key_matrix), 5);
	
	for(i=0; i<40; i++)
		if((key_matrix>>i)&0x1)
			break;
	
	if(i==40)
		keypress = PAN_KEY_INVALID;
	else
		keypress = 0x00000000|(1<<i);

	if (key_matrix == 0x80000)		// ch+
		keypress = 0xFFFF0054;	
	if (key_matrix == 0x2000000)	// power
		keypress = 0xFFFF0044;
	if (key_matrix == 0x10)		// ch-
		keypress = 0xFFFF005c;
#endif

	/* Some key input */
	if (keypress != PAN_KEY_INVALID)
	{
	//libc_printf("Some key input keypress=%x \n",keypress);
		/* If is the same key, count it */
		if (tp->keypress_bak == keypress)
		{
			tp->keypress_cnt++;
			if (tp->keypress_cnt == 2)
			{
				key.type = PAN_KEY_TYPE_PANEL;
				key.state = PAN_KEY_PRESSED;
				key.count = tp->key_cnt;
				key.code = tp->keypress_bak;
				pan_buff_queue_tail(&key);
				tp->key_cnt++;
			}
			else if (tp->keypress_cnt == tp->keypress_intv)
			{
				tp->keypress_intv = tp->cnt_repeat/10;
				tp->keypress_cnt = 0;	/* Support continue press key */
			}
		}
		/* Else is a new key, backup it */
		else
		{
		//libc_printf("Else is a new key, backup it \n");
			if (tp->hw_info->intv_release & 1)	/* If intv_release is odd, pan key repeat enable */
			{
				if (tp->keypress_bak != PAN_KEY_INVALID)
				{
			   		key.type = PAN_KEY_TYPE_PANEL;
			   		key.state = PAN_KEY_RELEASE;
					key.count = 0;
					key.code = tp->keypress_bak;
					pan_buff_queue_tail(&key);
				}
			}
			tp->keypress_intv = tp->cnt_repeat_first/10;
			tp->keypress_bak = keypress;
			tp->keypress_num = tp->dis_id;
			tp->keypress_cnt = 1;
			tp->key_cnt = 0;
		}
	}
	/* No key input, if the same key switch to invalid, reset it */
	else if (/*tp->keypress_num == tp->dis_id &&*/ tp->keypress_bak != PAN_KEY_INVALID)
	{
		if (cnt++ > 5)
		{
			if (tp->hw_info->intv_release & 1)	/* If intv_release is odd, pan key repeat enable */
			{
		   		key.type = PAN_KEY_TYPE_PANEL;
		   		key.state = PAN_KEY_RELEASE;
				key.count = 0;
				key.code = tp->keypress_bak;
				pan_buff_queue_tail(&key);
			}
			tp->keypress_intv = tp->cnt_repeat_first/10;
			tp->keypress_bak = PAN_KEY_INVALID;
			tp->keypress_num = tp->hw_info->num_com;
			tp->keypress_cnt = 0;
			tp->key_cnt = 0;
			cnt = 0;
		}
	}
}

/*
* Name          :   pan_sm1668_esc_command()
* Description   :   Do ESC command
* Parameter     :   UINT8* data			: Command data
*                   UINT32 limit_len	: Length limit
* Return        :   UINT32				: command length
*/
static UINT32 pan_sm1668_esc_command(struct pan_device *dev, UINT8 *data, UINT32 limit_len)
{
	struct pan_sm1668_info *tp = (struct pan_sm1668_info *)dev->priv;
	struct pan_gpio_info *gp;
	UINT32 dp;

	/* Search ESC command untill no-ESC or reached data limit */
	for (dp = 0; dp < limit_len && data[dp] == 27; dp += 4)
	{	/* LBD operate command */
		if (PAN_ESC_CMD_LBD == data[dp + 1] || 'l' == data[dp + 1])
		{
			gp = &tp->hw_info->lbd[data[dp + 2]];
			if (tp->hw_info->type_kb & 0x02)	/* LED PIN is controlled by shifter */
			{
				tp->led_buff = ((tp->led_buff & ~(1 << gp->position)) |
					((~(gp->polar ^ data[dp + 3]) & 1) << gp->position));
			} else
			{
				HAL_GPIO_BIT_SET(gp->position, data[dp + 3]==0?(!gp->polar):gp->polar);
				//pan_common_gpio_set_bit(*(UINT8 *)(gp), data[dp + 3]);
			}
		} else if (PAN_ESC_CMD_LED == data[dp + 1] || 'e' == data[dp + 1])
		{
			tp->dis_buff[data[dp + 2]] = data[dp + 3];
		}
	}

	return dp;
}

/*
* Name          :   pan_sm1668_char_map()
* Description   :   Do string display
* Parameter     :   UINT8* data			: Command data
*                   UINT32 limit_len	: Length limit
* Return        :   UINT32				: string length
*/
static UINT32 pan_sm1668_char_map(struct pan_device *dev,
											 UINT8 *data, UINT32 len)
{
	struct pan_sm1668_info *tp = (struct pan_sm1668_info *)dev->priv;
	UINT32 pdata, pbuff;
	int i, j;
	UINT8 dot_flag = 0;

	pdata = 0;
	pbuff = 0;
	tp->dis_buff[tp->hw_info->pos_colon] = tp->blankmap;/* Clear colon flag */
	/* Search all string sector in data untill ESC or pbuf full */
	//libc_printf("displaystring:%s\n",data);
	while (pdata < len && data[pdata] != 27 && pbuff < dev->led_num)
	{
		if (data[pdata] == ':')		/* Process colon charactor */
		{
			dot_flag = 1;
			pdata++;
			continue;
		}
		if (data[pdata] == '.')		/* Process dot charactor */
		{
			tp->dis_buff[pbuff] = tp->dotmap;
			pdata++;
			pbuff++;
			continue;
		}
		/* Generate the bitmap */
		tp->dis_buff[pbuff] = tp->blankmap;	/* Pre-set buffer to NULL */
		for (j = 0; j < tp->bitmap_len; j++)
		{
			if(data[pdata] == tp->bitmap_list[j].character)
			{
				tp->dis_buff[pbuff] = tp->bitmap_list[j].bitmap;
				if (data[pdata + 1] == '.' && (pdata + 1) < len)
				{
					UINT32 k, l = 0;
					for(k=0; k<8; k++)
						if(tp->dotmap&(1<<k))
							l++;
					if(l==7)
						tp->dis_buff[pbuff] &= tp->dotmap;
					else
						tp->dis_buff[pbuff] |= tp->dotmap;
				}
				break;
			}
		}
		/* Move to next position */
		pbuff++;
		if (data[pdata + 1] == '.' && (pdata + 1) < len)
		{
			pdata += 2;
		} else
		{
			pdata += 1;
		}
	}
	if (dot_flag == 1)
		tp->dis_buff[tp->hw_info->pos_colon] &= tp->colonmap;


	//generate new display matrix
	if(tp->hw_info->num_com>5)
		tp->hw_info->num_com = 5;

	for(i=0; i<tp->hw_info->num_com;i++)
	{
#ifdef _BOARD_DB_C3047_T2_01V01_
		tp->new_dis_mem[i][0] = tp->dis_buff[i]<<START_SG_TO_LED;
		tp->new_dis_mem[i][1] = tp->dis_buff[i]>>(8-START_SG_TO_LED);	
#else
		tp->new_dis_mem[i][0] = tp->dis_buff[i];	
#endif
	}
	//update current display matrix
	for(i=0; i<tp->hw_info->num_com;i++)
	{
#ifdef _BOARD_DB_C3047_T2_01V01_
		if(tp->new_dis_mem[i][0] != tp->cur_dis_mem[i][0]||tp->new_dis_mem[i][1] != tp->cur_dis_mem[i][1])
		{
			if(i==0)
			{
				if(GRE_LED_CONTROL_SG<8)//show green led
				{
					tp->new_dis_mem[i][0]|=1<<GRE_LED_CONTROL_SG;
				}
				else
				{
					tp->new_dis_mem[i][1]|=1<<(GRE_LED_CONTROL_SG-8);
				}
				
			}

			tp->cur_dis_mem[i][0] = tp->new_dis_mem[i][0] ;
			tp->cur_dis_mem[i][1] = tp->new_dis_mem[i][1] ;

			//libc_printf("display %d bitmap:%x,%x\n",i,tp->cur_dis_mem[i][0],tp->cur_dis_mem[i][1]);
			pan_sm1668_update_led(i*2, &tp->cur_dis_mem[i][0], 2);
		}
#else
		if(tp->new_dis_mem[i][0] != tp->cur_dis_mem[i][0])
		{
			tp->cur_dis_mem[i][0] = tp->new_dis_mem[i][0] ;
			pan_sm1668_update_led(i*2, &tp->cur_dis_mem[i][0], 1);
		}

		if(i==0)//tp->new_dis_mem[i][1] != tp->cur_dis_mem[i][1])
		{
			tp->cur_dis_mem[i][1] = tp->new_dis_mem[i][1]=0x02 ;//0x02 ;
			pan_sm1668_update_led(i*2 +1, &tp->cur_dis_mem[i][1], 1);
		}
#endif
	}
	
	/* Display buffer full, stop display process */
	if (data[pdata] != 27 && pbuff == dev->led_num)
	{
		return len;
	}
	return pdata;
}

/*
* Name          :   pan_sm1668_display()
* Description   :   Set display data
* Parameter     :   char* disp
* Return        :   void
*/
static void pan_sm1668_display(struct pan_device *dev, char *data, UINT32 len)
{
	struct pan_sm1668_info *tp = (struct pan_sm1668_info *)dev->priv;
	UINT32 pdata = 0;

	if (tp->hw_info->hook_show)
	{
		len = tp->hw_info->hook_show(dev, data, len);
	}

	while (pdata < len)
	{
		if (data[pdata] == 27)			/* ESC command */
		{
			pdata += pan_sm1668_esc_command(dev, &(data[pdata]), len - pdata);
		} 
		else							/* String display */
		{
			pdata += pan_sm1668_char_map(dev, &(data[pdata]), len - pdata);
		}
	}
}

/*
* Name          :   pan_scan_callback()
* Description   :   This function is used for callback by some disabled IRQ app
* Parameter     :   struct pan_device *dev
* Return        :   void
*/
void pan_sm1668_scan_callback(struct pan_device *dev)
{
	static UINT32 last_tsc = 0;
	UINT32 cur_tsc;

	cur_tsc = read_tsc();
	if ((cur_tsc - last_tsc) / (/*SYS_CPU_CLOCK*/ (sys_ic_get_cpu_clock()*1000000)/ 400) == 0)
	{
		return;
	}
	last_tsc = cur_tsc;

	pan_sm1668_interrupt((UINT32)dev);
}

//#define DBG_LED_BMP
#if 0//def DBG_LED_BMP
/*
This function is based bitmap_table above to generate a new led bmp table
//
 *      ###b7##
 *    b2#     #b6
 *      ###b1##
 *    b3#     #b5
 *      ###b4##  #b0#
*/
static UINT8 led_bmp_mask[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};

#define SET_BIT(v, bitn, bitv) v |= (bitv<<bitn);
void pan_gen_led_bmp(struct led_bitmap *dest, UINT8 *led_bmp, UINT8 led_light)
{
    UINT16 i, j;
    for(i = 0; i < PAN_COMMON_CHAR_LIST_NUM; i++)
    {
        dest[i].bitmap = 0;
        for(j = 0; j < 8; j++)
        {
            if(!(bitmap_table[i].bitmap&led_bmp_mask[j]))
            {
                //This bit needs to be light
                SET_BIT(dest[i].bitmap, led_bmp[j], led_light);
            }
            else
            {
                //This bit needs to be dark
                SET_BIT(dest[i].bitmap, led_bmp[j], (!led_light));
            }
        }
    }

    for(i = 0; i < PAN_COMMON_CHAR_LIST_NUM; i++)
    {
        osal_delay(2000);
        LIBC_PRINTF("{'%c', 0x%02x}, ", dest[i].character, dest[i].bitmap);
        osal_delay(2000);
        if((i && (i%4 == 0)) || (i == 0))
            LIBC_PRINTF("\n");
    }
    LIBC_PRINTF("\n");
}
#endif
